﻿
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[ExecuteAlways]
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
public partial class ListView : UIBehaviour, ICanvasElement
{
    public struct ItemNode
    {
        //对应的ui
        public RectTransform rtf;
        //对应的数据条目索引
        public int dataIndex;

        public ItemNode(RectTransform rtf, int dataIndex)
        {
            this.rtf = rtf;
            this.dataIndex = dataIndex;
        }
    }

    struct ItemPosAndSize
    {
        public float size;
        public float bottomDis;

        public ItemPosAndSize(float size, float bottomDis)
        {
            this.size = size;
            this.bottomDis = bottomDis;
        }

        public float TopDis
        {
            get
            {
                float topDis = bottomDis - size;
                return topDis;
            }
        }
    
    }
    
    public delegate RectTransform ObtainItemDelegate(ListView listView, int index);
    public delegate void RecycleItemDelegate(ListView listView, RectTransform itemNode);

    public RectTransform m_BeginStub;
    public RectTransform m_EndStub;
    
    private ObtainItemDelegate m_OnObtainItem;
    private RecycleItemDelegate m_OnRecycleItem;
    
    private ScrollRect m_ScrollRect;
    private bool m_IsVertical;
    //TopToBottom或BottomToTop这种
    //private bool m_IsReverse;
    ///条目间隔
    private float m_ItemSpace;
    private float m_LeadPadding;
    ///滚动距离百分比, 值范围[0, 100]
    private int m_ScrollPercent;
    
    private List<ItemPosAndSize> m_ItemPosAndSizeList = new List<ItemPosAndSize>();
    private List<ItemNode> m_ItemNodeList = new List<ItemNode>();
    ///要展示的数据数量
    private int m_DataCount;
    public int m_LateUpdateFlag;
    public int m_AutoLayoutFlag;
    private float m_DefaultItemSize = 100;
    private bool m_AdjustBeginStubSizeFlag;
    private bool m_AdjustEndStubSizeFlag;
    
    protected override void Awake()
    {
        base.Awake();
        m_ScrollRect = GetComponent<ScrollRect>();
#if UNITY_EDITOR
        ListViewUtil.CheckConfig(m_ScrollRect);
#endif
        m_IsVertical = !m_ScrollRect.horizontal;
        HorizontalOrVerticalLayoutGroup layoutGroup = null;
        if (m_IsVertical)
        {
            layoutGroup = m_ScrollRect.content.GetComponent<VerticalLayoutGroup>();
            m_LeadPadding = layoutGroup.padding.top;
        }
        else
        {
            layoutGroup = m_ScrollRect.content.GetComponent<HorizontalLayoutGroup>();
            m_LeadPadding = layoutGroup.padding.left;
        }
        m_ItemSpace = layoutGroup.spacing;
        m_ScrollRect.onValueChanged.AddListener(OnValueChanged_ScrollRect);
    }

    public void SetItemDelegate(ObtainItemDelegate onObtain, RecycleItemDelegate onRecycle)
    {
        m_OnObtainItem = onObtain;
        m_OnRecycleItem = onRecycle;
    }

    private void RecycleItem(RectTransform itemNode)
    {
        if (null != m_OnRecycleItem)
        {
            m_OnRecycleItem(this, itemNode);
        }
        else
        {
            GameObject.Destroy(itemNode.gameObject);
        }
    }

    public void RefreshItems(int firstDataIndex)
    {
        m_LateUpdateFlag = 2;
        if (m_IsVertical)
            RefreshItems_Vertical(firstDataIndex);
        else
            RefreshItems_Horizontal();
    }
    
    //index范围[0, ItemNodeCount), 注意和DataIndex区分
    public ItemNode GetItemNodeAt(int index)
    {
        return m_ItemNodeList[index];
    }
    
    public int ItemNodeCount
    {
        get { return m_ItemNodeList.Count; }
    }

    //offset: >0为往上, <0为往下
    public void ScrollToDataIndex(int dataIndex, float offset)
    {
        if (m_IsVertical)
            ScrollToDataIndex_Vertical(dataIndex, offset);
        else
            ScrollToDataIndex_Horizontal(dataIndex, offset);
    }

    public int GetDataIndexByScrollDis(float scrollDis)
    {
        if (m_IsVertical)
            return GetDataIndexByScrollDis_Vertical(scrollDis);
        else
            return GetDataIndexByDis_Horizontal(scrollDis);
    }

    public int DataCount
    {
        get { return m_DataCount; }
        set { m_DataCount = value; }
    }

    public float DefaultItemSize
    {
        get { return m_DefaultItemSize; }
        set { m_DefaultItemSize = value; }
    }

    //LastDataBottomDis?
    public float ContentSize
    {
        get
        {
            int endIndex = m_ItemPosAndSizeList.Count - 1;
            float ret = m_ItemPosAndSizeList[endIndex].bottomDis;
            return ret;
        }
    }

    public float ViewportSize
    {
        get
        {
            if (m_IsVertical)
                return ViewportSize_Vertical;
            else
                return ViewportSize_Horizontal;
        }
    }
    
    public float ScrollDistance
    {
        get
        {
            if (m_IsVertical)
                return ScrollDistance_Vertical;
            else
                return ScrollDistance_Horizontal;
        }
    }
    
    private void OnValueChanged_ScrollRect(Vector2 vec2)
    {
        if (m_IsVertical)
            OnValueChanged_ScrollRect_Vertical(vec2);
        else
            OnValueChanged_ScrollRect_Horizontal(vec2);
    }

    //如果外部调用了ScrollRect上的onValueChanged.RemoveAllListeners(), 则要调用该函数来恢复滚动监听
    public void ReAddScrollListener()
    {
        var unityEvent = m_ScrollRect.onValueChanged;
        unityEvent.RemoveListener(OnValueChanged_ScrollRect);
        unityEvent.AddListener(OnValueChanged_ScrollRect);
    }
    
    public void UpdateItemsPosAndSizeNextFrame()
    {
        m_LateUpdateFlag = 1;
    }
    
    public void UpdateItemsPosAndSize()
    {
        if (m_IsVertical)
            UpdateItemsPosAndSize_Vertical();
        else
            UpdateItemsPosAndSize_Horizontal();
    }

    public void Rebuild(CanvasUpdate executing)
    {
        Debug.Log($"{GetType().Name}: Rebuild: {executing}");
    }

    public void LayoutComplete()
    {
        Debug.Log($"{GetType().Name}: LayoutComplete");
    }

    public void GraphicUpdateComplete()
    {
        Debug.Log($"{GetType().Name}: GraphicUpdateComplete");
    }

    protected override void OnTransformParentChanged()
    {
        base.OnTransformParentChanged();
        Debug.Log($"{GetType().Name}: OnTransformParentChanged");
    }

    protected override void OnRectTransformDimensionsChange()
    {
        base.OnRectTransformDimensionsChange();
        Debug.Log($"{GetType().Name}: OnRectTransformDimensionsChange");
        m_LateUpdateFlag = 2;
    }
    
    private void LateUpdate()
    {
        if (m_LateUpdateFlag > 0)
        {
            m_LateUpdateFlag--;
            if (0 == m_LateUpdateFlag)
            {
                if (m_IsVertical)
                    UpdateScrollPercent_Vertical();
                UpdateItemsPosAndSize();
            }
        }
    }

    private void PrintAllItemPosAndSize(string tag)
    {
        Debug.Log($"========== PrintAllItemPosAndSize: {tag}");
        for (int i = 0; i < m_ItemPosAndSizeList.Count; ++i)
        {
            var itemPosAndSize = m_ItemPosAndSizeList[i];
            Debug.Log($"dataIndex: {i}: itemSize:{itemPosAndSize.size}, bottomDis:{itemPosAndSize.bottomDis}");
        }
        Debug.Log($"contentSize: {m_ScrollRect.content.rect.size.y}");
        Debug.Log($"==========");
    }
    
}
